package com.yst.feign1.config;

import com.fasterxml.jackson.databind.JavaType;
import com.yst.feign1.common.ApiResponse;
import feign.FeignException;
import feign.Response;
import feign.Util;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;

import java.io.IOException;
import java.lang.reflect.Type;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Date;

/**
 * feign请求结果 解码器
 */
@Slf4j
@Component
public class FeignResultDecoder implements Decoder {

    private final JsonMapper objectMapper = new JsonMapper();

    @Override
    public Object decode(Response response, Type type) throws IOException, DecodeException, FeignException {
        Response.Body body = response.body();
        if (body == null) {
            throw new DecodeException(response.status(), "没有返回有效的数据", response.request());
        }
        String bodyStr = Util.toString(body.asReader(Util.UTF_8));
        //对结果进行转换
        ApiResponse apiResponse = null;
        try {
            if (type instanceof Class) {
                apiResponse = objectMapper.readValue(bodyStr, (Class<ApiResponse>) type);
            }
            if (type instanceof ParameterizedTypeImpl) {
                Type[] actualTypeArguments = ((ParameterizedTypeImpl) type).getActualTypeArguments();
                Class[] genericClassArr = new Class[0];
                JavaType javaType = null;
                if (actualTypeArguments != null && actualTypeArguments.length > 0) {
                    if (actualTypeArguments[0] instanceof Class) {
                        genericClassArr = Arrays.stream(actualTypeArguments).map(e -> ((Class) e)).toArray(Class[]::new);
                        javaType = objectMapper.getTypeFactory().constructParametricType(ApiResponse.class, genericClassArr);
                    }
                    if (actualTypeArguments[0] instanceof ParameterizedTypeImpl) {
                        JavaType[] javaTypes = Arrays.stream(actualTypeArguments).map(e -> ((ParameterizedTypeImpl) e)).map(e -> {
                            Class[] arr = Arrays.stream(e.getActualTypeArguments()).map(c -> ((Class) c)).toArray(Class[]::new);
                            return objectMapper.getTypeFactory().constructParametricType(e.getRawType(), arr);
                        }).toArray(JavaType[]::new);
                        javaType = objectMapper.getTypeFactory().constructParametricType(ApiResponse.class, javaTypes);
                    }
                }
                apiResponse = objectMapper.readValue(bodyStr, javaType);
            }
        } catch (Exception e) {
            log.error("", e);
            throw e;
        }
        //如果返回错误，且为内部错误，则直接抛出异常
        if (apiResponse.getCode() != 200) {
            throw new FeignFailResponseException(apiResponse, response.request());
        }
        return apiResponse;
    }

}
